import * as ts from 'typescript';

import { GetSw2ts } from '../config';
import { leetEnumsCreator } from './commom';
import {
	createEnumDeclaration,
	createFunctionDeclaration,
	createImportDeclaration,
	createInterfaceDeclaration,
	createJSDocComment,
	createJSDocCommentFunction,
	createTypeAliasDeclaration,
	deCallbackRef,
} from './factory';
import { traverse } from './handleSchema';
import {
	filterStateAble, findIsUrl
} from './inSearchFor';
import { handleSchema2JSON } from './jsonSchema';
import logger from './logger';

/**
 * Notes - Generate Request API
 * @param data SwaggerSpec
 * @returns (ts.ImportDeclaration | ts.FunctionDeclaration | ts.JSDoc)[]
 */
export function GenerateAPI2dts (data: SwaggerSpec) {
	const Sw2tsConf = GetSw2ts();
	const dataSchema = handleSchema2JSON(data.paths);

	Sw2tsConf.hasContext = new Set<string>();
	const ablePass = (Sw2tsConf.namespace ?? []).length === 0;
	const list: (ts.ImportDeclaration | ts.FunctionDeclaration | ts.JSDoc)[] = [];

	for (const key in dataSchema) {
		const leetSchema = dataSchema[key];
		if (ablePass || findIsUrl(leetSchema.url, Sw2tsConf.namespace)) {
			const {
				summary, parameters
			} = leetSchema;
			list.push(createJSDocCommentFunction(summary, parameters));
			list.push(createFunctionDeclaration(leetSchema, ts.SyntaxKind.ExportKeyword));
			deCallbackRef((ref: string) => {
				Sw2tsConf.hasContext.add(ref);
				Sw2tsConf.requireCtx.add(ref);
			});
			traverse((parameters ?? []).concat(leetSchema.response || []), Sw2tsConf.hasContext);
		}
	}

	list.unshift(createImportDeclaration('../request', ['RequestConfig'], 'API'));

	return list;
}

/**
 * Notes - Generate Declare InterfaceDeclaration
 * @param data SwaggerSpec
 * @returns (ts.InterfaceDeclaration | ts.EnumDeclaration | ts.JSDoc)[]
 */
export function GenerateInterface2dts (data: SwaggerSpec) {
	const list: (ts.InterfaceDeclaration | ts.EnumDeclaration | ts.JSDoc)[] = [];

	const Sw2tsConf = GetSw2ts();
	const {
		ableState, hasContext
	} = filterStateAble(Sw2tsConf, data);
	const iterators = Sw2tsConf.local ? hasContext : Object.keys(ableState);

	for (const key of iterators) {
		const define = ableState[key] as DefinitionSpec;
		// 针对中文类名，进行提示处理
		if (/[\u4e00-\u9fa5]+/.test(key)) {
			logger.warn(`Logger: 请联系后端开发者处理异常类名, 即: ${key}`);
		}

		if (define.description) list.push(createJSDocComment(define.description));
		list.push(createInterfaceDeclaration(ableState, key, ts.SyntaxKind.DeclareKeyword));
		leetEnumsCreator((leetEnums: AliasEnum[]) => {
			for (const iterator of leetEnums) {
				if (iterator.description) {
					list.push(createJSDocComment(iterator.description));
				}
				list.unshift(createEnumDeclaration(iterator));
			}
		});
	}

	return list;
}

/**
 * Notes - Generate Declare TypeAliasDeclaration
 * @param data SwaggerSpec
 * @returns (ts.TypeAliasDeclaration | ts.EnumDeclaration | ts.JSDoc)[]
 */
export function GenerateTypeAlias2dts (data: SwaggerSpec) {
	const list: (ts.TypeAliasDeclaration | ts.EnumDeclaration | ts.JSDoc)[] = [];

	const Sw2tsConf = GetSw2ts();
	const {
		ableState, hasContext
	} = filterStateAble(Sw2tsConf, data);
	const iterators = Sw2tsConf.local ? hasContext : Object.keys(ableState);

	for (const key of iterators) {
		const define = ableState[key] as DefinitionSpec;
		// 针对中文类名，进行提示处理
		if (/[\u4e00-\u9fa5]+/.test(key)) {
			logger.warn(`Logger: 请联系后端开发者处理异常类名, 即: ${key}`);
		}

		if (define.description) list.push(createJSDocComment(define.description));
		list.push(createTypeAliasDeclaration(ableState, key, ts.SyntaxKind.DeclareKeyword));
		leetEnumsCreator((leetEnums: AliasEnum[]) => {
			for (const iterator of leetEnums) {
				if (iterator.description) {
					// list.push(createJSDocComment(iterator.description));
				}
				list.unshift(createEnumDeclaration(iterator));
			}
		});
	}

	return list;
}
